#pragma once
#include <ctype.h>
#include <getopt.h>
#include <libintl.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>

#define C_BOLD "\033[1m"
#define C_ERROR "\033[1m\033[31m"
#define C_HIGHLIGHT "\033[1m\033[32m"
#define ENDCOLOR "\033[0m"

typedef struct winsize win_size;
static int args_hideinfo = 0, args_showhelp = 0, args_showversion = 0;

int display_num(char *buffer, float value) {
	if ((int)value == value) {
		return snprintf(buffer, sizeof(buffer), "%d", (int)value);
	} else {
		char string[64], string1[64];
		snprintf(string, 64, "%f", value);
		for (int i = 1; i <= strlen(string); i ++) {
			strncpy(string1, string, i);
			if ((float)atof(string1) == value) {
				return snprintf(buffer, sizeof(buffer), "%s", string1);
			}
		}
	}
}

float fround(float x, int n) {
	float a = powf(10, n);
	float b = 1 / a;
	return (int)(x * a) * b;
}

char *get_compiler() {
#if defined(__ARMCC_VERSION)
	return "ARM C/C++";
#elif defined(__BORLANDC__)
	return "Borland C++";
#elif defined(__DMC__)
	return "DMC++";
#elif defined(__INTEL_COMPILER)
	return "Intel C++";
#elif defined(__GNUC__) || defined(__APPLE_CC__)
	return "GCC";
#elif defined(_MSC_VER)
	return "Visual C++";
#else
	return "Other compiler";
#endif
}

int get_var(char *name) {
	if (!name) {
		puts(gettext("Please select a variable."));
		return -1;
	}
	if (isalpha(name[0]) != 0) {
		return toupper(name[0]) - 'A';
	} else {
		printf(gettext("\"%c\" isn't a variable.\n"), name[0]);
		return -1;
	}
}

void get_version(int *major, int *minor, int *patch) {
	*major = 1; *minor = 0; *patch = 0;
}

int get_win_size(struct winsize *win) {
	int err = ioctl(0, TIOCGWINSZ, (char *) win);
	return err;
}

int is_eligible_with_one_condition(float left, char *condition) {
	int op = 0;
	char *right_s = condition, *end;
	float right;
	if (strncmp(condition, ">=", 2) == 0) {
		op = 0; right_s += 2;
	} else if (strncmp(condition, "<=", 2) == 0) {
		op = 1; right_s += 2;
	} else if (strncmp(condition, ">", 1) == 0) {
		op = 2; right_s += 1;
	} else if (strncmp(condition, "<", 1) == 0) {
		op = 3; right_s += 1;
	} else if (strncmp(condition, "=", 1) == 0) {
		op = 4; right_s += 1;
	} else if (strncmp(condition, "!=", 2) == 0) {
		op = 5; right_s += 2;
	} else {
		printf(gettext("Can't parse expression: \"%s\".\n"), condition);
		return -1;
	}
	right = strtof(right_s, &end);
	if ((right == 0) && (end == right_s)) {
		printf(gettext("Invalid number: \"%s\".\n"), right_s);
		return -1;
	}
	switch (op) {
		case 0:
			return isgreaterequal(left, right);
		case 1:
			return islessequal(left, right);
		case 2:
			return isgreater(left, right);
		case 3:
			return isless(left, right);
		case 4:
			return !islessgreater(left, right);
		case 5:
			return islessgreater(left, right);
	}
}

int is_eligible(float number, char *c1, char *op, char *c2) {
	int r1, r2;
	r1 = is_eligible_with_one_condition(number, c1);
	if (r1 == -1) {
		return -1;
	}
	if (!op && !c2) {
		return r1;
	} else if (op && !c2) {
		puts(gettext("`op` and `condition` must both exist."));
		return -1;
	} else {
		r2 = is_eligible_with_one_condition(number, c2);
		if (r2 == -1) {
			return -1;
		}
		if ((strcmp(op, "and") == 0) || (strcmp(op, "&&") == 0)) {
			return r1 && r2;
		} else if ((strcmp(op, "or") == 0) || (strcmp(op, "||") == 0)) {
			return r1 || r2;
		} else {
			printf(gettext("Operator \"%s\" is invalid.\n"), op);
			return -1;
		}
	}
}

void parse_args(int argc, char *argv[]) {
	int opt;
	static struct option longopts[] = {
		{"help", no_argument, NULL, 'h'},
		{"version", no_argument, NULL, 'V'},
		{NULL, 0, NULL, 0}
	};
	while ((opt = getopt_long(argc, argv, "Vhq", longopts, NULL)) != -1) {
		switch (opt) {
			case 'V':
				args_showversion = 1;
				break;
			case 'h':
				args_showhelp = 1;
				break;
			case 'q':
				args_hideinfo = 1;
				break;
			default:
				fprintf(stderr, gettext("Try \"%s --help\" for more information.\n"), argv[0]);
				exit(EXIT_FAILURE);
		}
	}
}

